package com.atguigu.distributed.lock.leecode;


import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;

/**
 * 力扣中等46：全排列
 */
public class AllSort {
    List<List<Integer>> result = new ArrayList<>();
    LinkedHashSet<Integer> linkedHashSet = new LinkedHashSet<>();

    public List<List<Integer>> permute(int[] nums) {
        permuteHelper(nums);
        return result;
    }

    public void permuteHelper(int[] nums) {
        if (linkedHashSet.size() == nums.length){
            result.add(new ArrayList<>(linkedHashSet));
            return;
        }
        for (int i = 0; i < nums.length; i++) {
            //此处的精妙之处在于，在遍历到第三个元素时，第四个元素已经被删除了，
            // 所以第三个也被删除之后，再遍历到第四个时已经判断不包含第四个了，会再次添加第四个元素
            if (linkedHashSet.contains(nums[i]))continue;
            linkedHashSet.add(nums[i]);
            permuteHelper(nums);
            //此处为回溯的关键一步，即不断的撤销以便达到回溯的效果
            linkedHashSet.remove(nums[i]);
        }
    }
    public List<List<Integer>> premute2(int[] nums){
        premuteHelper2(nums);
        return result;
    }
    public void premuteHelper2(int[] nums){
        if(linkedHashSet.size()==nums.length){
            result.add(new ArrayList<>(linkedHashSet));
        }
        for (int i = 0; i < nums.length; i++) {
            if(linkedHashSet.contains(nums[i])){
                continue;
            }
            linkedHashSet.add(nums[i]);
            premuteHelper2(nums);
            linkedHashSet.remove(nums[i]);
        }
    }
    public static void main(String[] args) {
        int[] nums = {1,2,3,4};
        AllSort allSort = new AllSort();
        List<List<Integer>> permute = allSort.permute(nums);
        System.out.println("res==>"+ permute);
    }
//    public List<List<Integer>> permute(int[] nums) {
//        int len = nums.length;
//        // 使用一个动态数组保存所有可能的全排列
//        List<List<Integer>> res = new ArrayList<>();
//        if (len == 0) {
//            return res;
//        }
//
//        boolean[] used = new boolean[len];
//        List<Integer> path = new ArrayList<>();
//
//        dfs(nums, len, 0, path, used, res);
//        return res;
//    }

    private void dfs(int[] nums, int len, int depth,
                     List<Integer> path, boolean[] used,
                     List<List<Integer>> res) {
        if (depth == len) {
            res.add(path);
            return;
        }

        // 在非叶子结点处，产生不同的分支，这一操作的语义是：在还未选择的数中依次选择一个元素作为下一个位置的元素，这显然得通过一个循环实现。
        for (int i = 0; i < len; i++) {
            if (!used[i]) {
                path.add(nums[i]);
                used[i] = true;

                dfs(nums, len, depth + 1, path, used, res);
                // 注意：下面这两行代码发生 「回溯」，回溯发生在从 深层结点 回到 浅层结点 的过程，代码在形式上和递归之前是对称的
                used[i] = false;
                path.remove(path.size() - 1);
            }
        }
    }

}
